/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package semant.second_pass;

import semant.Env;
import symbol.ClassInfo;
import symbol.Symbol;
import syntaxtree.ClassDecl;
import syntaxtree.ClassDeclExtends;
import syntaxtree.Program;
import syntaxtree.VisitorAdapter;
import util.List;

class InheritanceBuilder extends VisitorAdapter {
	
	private Env env;
	private List<ClassDecl> classes;

    public InheritanceBuilder(Env e, List<ClassDecl> c) {
    	super();
    	
		env = e;
		classes = c;
	}

	static void secondPass(Env e, Program p) {
        InheritanceBuilder b = new InheritanceBuilder(e, p.classList);
        
        for (List<ClassDecl> classes = p.classList;classes!=null;classes = classes.tail) {
            classes.head.accept(b);
        }

    }
	
	@Override
	public void visit(ClassDeclExtends node) {
		Symbol name = Symbol.symbol(node.name.s);
		Symbol base = Symbol.symbol(node.superClass.s);
		
		ClassInfo cinfo = env.classes.get(name);
		ClassInfo sinfo = env.classes.get(base);
		
		if (cinfo == null)
			return;
		
		if (cinfo.base != null)
			return;
		
		if (sinfo == null) {
			env.err.Error(node, new Object[]{
				"Classe \'" + name + "\' deriva da classe nao declarada: \'" + base + "\'."  
			});
		} else {
			if (!canInheriteFrom(sinfo, cinfo)) {
				env.err.Error(node, new Object[]{
					"Heranca circular detectada entre \'" + name + "\' e \'" + base + "\'."	
				});
			} else {
				cinfo.setBase(sinfo);
			}
		}
		
	}
	
	public boolean canInheriteFrom(ClassInfo base, ClassInfo derived) {
		ClassInfo baseTmp = base;
		
		while (base != null) {
			if (base.name == derived.name)
				return false;
			else
				base = base.base;
		}
		
		base = baseTmp;
		
		return true;
	}

}
